package raoxuefeng.hw.hw_music_raoxuefeng;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.PowerManager;
import android.os.RemoteException;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class MusicService extends Service implements Constants,Runnable,
        MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnSeekCompleteListener
{

    private static final String TAG = MusicService.class.getSimpleName();
    private Messenger mMessenger = new Messenger(new IncomingHandler());
    ArrayList<Messenger> mClients = new ArrayList<>();

    private MediaPlayer mMediaPlayer;

    private List<MusicInfo> mMusicInfos = new ArrayList<>();
    private MusicLoader mMusicLoader;
    private int mCurrentPlaySongId = 0;

    private int mSeekToPosition = 0;

    void playNext()
    {
        if(++mCurrentPlaySongId <= mMusicInfos.size() )
        {
            mCurrentPlaySongId++;
            playThisSong(mCurrentPlaySongId);
        }
    }
    void playPrevious()
    {
        if(--mCurrentPlaySongId >= 0)
        {
            mCurrentPlaySongId--;
            playThisSong(mCurrentPlaySongId);
        }
    }

    private void createMediaPlayerIfNeeded() {
        Log.d(TAG, "createMediaPlayerIfNeeded. needed? " + mMediaPlayer);
        if (mMediaPlayer == null) {
            mMediaPlayer = new MediaPlayer();

            // Make sure the media player will acquire a wake-lock while
            // playing. If we don't do that, the CPU might go to sleep while the
            // song is playing, causing playback to stop.
            mMediaPlayer.setWakeMode(this.getApplicationContext(),
                    PowerManager.PARTIAL_WAKE_LOCK);

            // we want the media player to notify us when it's ready preparing,
            // and when it's done playing:
            mMediaPlayer.setOnPreparedListener(this);
            mMediaPlayer.setOnCompletionListener(this);
            mMediaPlayer.setOnErrorListener(this);
            mMediaPlayer.setOnSeekCompleteListener(this);
        } else {
            mMediaPlayer.reset();
        }
    }
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate MusicService!!!");

        //get song list.
        mMusicLoader = MusicLoader.instance(this.getContentResolver());
        mMusicInfos = mMusicLoader.getMusicList();


        // dump music info
//        for(int i= 0; i<mMusicInfos.size(); i++)
//        {
//            Log.e(TAG, i + ": " + mMusicInfos.get(i).getTitle());
//        }

        //mMediaPlayer = MediaPlayer.create(this, R.raw.libai);

//        Notification notification = new Notification(R.drawable.ic_launcher,"来通知了……", System.currentTimeMillis());
//        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, MusicService.class), 0);
////        notification.setLatestEventInfo(this, "标题","内容", pendingIntent);
////        startForeground(1, notification);
//
//
//        NotificationCompat.Builder mBuilder =
//                new NotificationCompat.Builder(this)
//                        .setSmallIcon(R.drawable.dmr_musicbg1)
//                        .setContentTitle("My Music Player")
//                        .setContentText("Song Name");
//
//        mBuilder.setContentIntent(pendingIntent);
//        NotificationManager mNotifyMgr =
//                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//// Builds the notification and issues it.
//        mNotifyMgr.notify(1, mBuilder.build());

        Log.e(TAG, "Activity thread id:" + Thread.currentThread().getId());

//        startForeground(1, );
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand");
//        mMediaPlayer.start();
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        Log.e(TAG, "onDestroy");
        // Relax all resources
        relaxResources(true);
        stopForeground(true);
        super.onDestroy();
    }

    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
        Log.e(TAG, "on ReBind!!!");
        notifyUpdatePlayStatus();
    }

    private void notifyUpdatePlayStatus() {
        Message msg = Message.obtain(null, NOTIFY_UPDATE_PLAY_STATUS);
        msg.arg1 = mCurrentPlaySongId;
        if(mMediaPlayer!=null && mMediaPlayer.isPlaying())
        {
            msg.arg2 = 1;//is playing.
        }else{
            msg.arg2 = 0;// not playing
        }
        sendMsgToAllClients(msg);
    }

    @Override
    public IBinder onBind(Intent intent) {
        //Return the communication channel to the service.
        Log.e(TAG, "onBind called.");
        return mMessenger.getBinder();
    }

    @Override
    public void onCompletion(MediaPlayer mp) {
        /* 播放完当前歌曲，自动播放下一首 */

        if (++mCurrentPlaySongId >= mMusicInfos.size())
        {
            Toast.makeText(MusicService.this, "已到最后一首歌曲", Toast.LENGTH_SHORT)
                    .show();
            mCurrentPlaySongId--;
            //update SeekBar
            updateSeekBarProgress(0);
        } else {
            playNext();
        }
    }

    private void playThisSong(int id) {
        createMediaPlayerIfNeeded();
        //check id valid?
        if(id < 0 || id > mMusicInfos.size()-1)
        {
            Log.e(TAG, "playThisSong: invalid song id !!! id = " + id);
        }
        mCurrentPlaySongId = id;
        if(mMediaPlayer!=null)
        {
            if(mMediaPlayer.isPlaying())
            {
                mMediaPlayer.stop();
            }

        }else
        {
            Log.e(TAG, "!!! mMediaPlayer is NULL !!!");
            return;
        }

        String UriMusic = mMusicInfos.get(mCurrentPlaySongId).getUrl();
        Log.e(TAG, "UriMusic: " + UriMusic);
        try {
            mMediaPlayer.setDataSource(this, Uri.parse(UriMusic));
        } catch (IOException e) {
            Log.e(TAG, "set DataSource Failed!!! UriMusic: " + UriMusic);
            e.printStackTrace();
        }

        try {
            mMediaPlayer.prepare();
        } catch (IOException e) {
            Log.e(TAG, "prepare() failed !!!");
            e.printStackTrace();
        }
        mMediaPlayer.seekTo(mSeekToPosition);
        mSeekToPosition = 0;
        mMediaPlayer.start();
        new Thread(this).start();//run() used to update seekbar progress.
    }

    private void sendMsgToAllClients(Message msg)
    {
        try {
            for ( Messenger m:mClients
                    ) {
                m.send(msg);
            }

        } catch (RemoteException e) {
            Log.e(TAG, "Send Msg to Clients Failed !!!");
            e.printStackTrace();
        }
    }
    private void updateSeekBarProgress(int progress) {
        Log.d(TAG, "update SeekBar Progress: " + progress);

        Message msg = Message.obtain(null, NOTIFY_UPDATE_PROGRESS);
        msg.arg1 = progress;
        sendMsgToAllClients(msg);
    }

    @Override
    public void run() {
        int CurrentPosition = 0;// 设置默认进度条当前位置
        int total = mMediaPlayer.getDuration();//
        while (mMediaPlayer != null && CurrentPosition < total) {
            try {
                Thread.sleep(200);

                if (mMediaPlayer != null) {
                    CurrentPosition = mMediaPlayer.getCurrentPosition();
                    //Log.e(TAG, "CurrentPosition: " + CurrentPosition + "Total: " + total);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            updateSeekBarProgress(100 * CurrentPosition/total);
        }

    }


    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        return false;
    }

    @Override
    public void onPrepared(MediaPlayer mp) {

    }

    @Override
    public void onSeekComplete(MediaPlayer mp) {

    }

    private void relaxResources(boolean releaseMediaPlayer) {
        Log.d(TAG, "relaxResources. releaseMediaPlayer=" + releaseMediaPlayer);

        // stop and release the Media Player, if it's available
        if (releaseMediaPlayer && mMediaPlayer != null) {
            mMediaPlayer.reset();
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
    }
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg)
        {
            switch (msg.what) {
                case CMD_REGISTER_CLIENT: {
                    Log.e(TAG, "recv CMD_REGISTER_CLIENT");

                    if (mClients.contains(msg.replyTo)) {
                        Log.e(TAG, msg.replyTo.toString() + " already regist");
                        return;
                    }
                    mClients.add(msg.replyTo);
                    Log.e(TAG, "receive CMD_REGISTER_CLIENT, mClients size: " + mClients.size());
                    if (mClients.size() > 1) {
                        Log.e(TAG, "BUG: mClients size too large!!! " + mClients.size());
                    }
                }
                break;
                case CMD_UNREGISTER_CLIENT:
                    Log.i(TAG, "receive CMD_UNREGISTER_CLIENT");
                    mClients.remove(msg.replyTo);
                    break;
                case CMD_PAUSE_SONG:
                    Log.e(TAG, "CMD_PAUSE");
                    if(mMediaPlayer==null || !mMediaPlayer.isPlaying())
                    {
                        Log.e(TAG, "ERROR receiving !!! CMD_PAUSE");
                        return;
                    }else{
                        mMediaPlayer.pause();
                        relaxResources(false);
                    }
                    break;
                case CMD_CONTINUE_PLAY:
                    Log.e(TAG, "CMD_CONTINUE_PLAY");
                    if(mMediaPlayer==null || mMediaPlayer.isPlaying())
                    {
                        Log.e(TAG, "ERROR receiving !!! CMD_CONTINUE_PLAY");
                        return;
                    }else{
                        mMediaPlayer.seekTo(mSeekToPosition);
                        mSeekToPosition = 0;
                        mMediaPlayer.start();
                        Log.e(TAG, "!!! Continue Playing");
                    }
                    break;
                case CMD_SEEK_TO:
                    SeekToPos(msg.arg1);
                    break;
                case CMD_PLAY_THE_SONG:
                    //start play from the beginning.
                    Log.e(TAG, "CMD_PLAY_THE_SONG id: " + msg.arg1);
                    playThisSong(msg.arg1);
                    break;
                case CMD_PLAY_NEXT:
                    playNext();
                    break;
                case CMD_PLAY_PREV:
                    playPrevious();
                    break;

                default:
                    super.handleMessage(msg);
            }
            notifyUpdatePlayStatus();
        }
    }

    private void SeekToPos(int pos) {
        mSeekToPosition = pos;
        if(mMediaPlayer!=null)
        {
            mMediaPlayer.seekTo((int)(pos/100.0 * mMediaPlayer.getDuration()));
        }
    }
}
